﻿using System.Diagnostics;
using System.Net.Sockets;
using System.Threading.Channels;

namespace SocketCore.Common.Event;

public sealed class SocketEventHub : IAsyncDisposable
{
    private readonly Channel<SocketEventArgs> _eventChannel;
    private readonly CancellationTokenSource _cts = new();
    private bool _disposed = false;

    #region 事件

    /// <summary>
    /// 统一的事件处理器
    /// </summary>
    public event EventHandler<SocketEventArgs>? OnEvent;

    /// <summary>
    /// 客户端连接事件
    /// </summary>
    public event EventHandler<SocketClientConnect>? ClientConnect;

    /// <summary>
    /// 心跳检测事件
    /// </summary>
    public event EventHandler<SocketHeartbeatMessage>? HeartbeatMessage;

    /// <summary>
    /// Log事件
    /// </summary>
    public event EventHandler<SocketLogMessage>? LogMessage;

    /// <summary>
    /// 消息事件
    /// </summary>
    public event EventHandler<SocketClientMessage>? MessageReceived;

    /// <summary>
    /// 客户端断开连接事件
    /// </summary>
    protected internal event EventHandler<Socket>? HeartbeatTimeout;

    /// <summary>
    /// 客户端断开连接通知（服务端使用）
    /// </summary>
    protected internal event EventHandler<Socket>? ClientDisconnected;

    #endregion

    #region 回调

    /// <summary>
    /// 发送心跳检测回调方法
    /// </summary>
    protected internal Action<Socket, CancellationToken>? SendHeartbeatCallback;

    /// <summary>
    /// 重连回调方法（客户端使用）
    /// </summary>
    protected internal Action? ConnectionLost { get; set; }

    #endregion

    public SocketEventHub()
    {
        _eventChannel = Channel.CreateUnbounded<SocketEventArgs>(new UnboundedChannelOptions
        {
            SingleReader = false,
            SingleWriter = false,
            AllowSynchronousContinuations = false
        });

        _ = ProcessEventsAsync(_cts.Token);
    }

    public void RaiseEvent(SocketEventType eventType, object data)
    {
        ObjectDisposedException.ThrowIf(_disposed, this);

        var eventArgs = new SocketEventArgs(eventType, data);
        OnEvent?.Invoke(this, eventArgs);
        _eventChannel.Writer.TryWrite(eventArgs);
    }

    private async Task ProcessEventsAsync(CancellationToken cancellationToken)
    {
        await foreach (var eventArgs in _eventChannel.Reader.ReadAllAsync(cancellationToken))
        {
            try
            {
                switch (eventArgs.Type)
                {
                    case SocketEventType.Connect when eventArgs.GetData<SocketClientConnect>() is { } connectMessage:
                        ClientConnect?.Invoke(this, connectMessage);
                        break;

                    case SocketEventType.Heartbeat when eventArgs.GetData<SocketHeartbeatMessage>() is { } heartbeatMessage:
                        HeartbeatMessage?.Invoke(this, heartbeatMessage);
                        break;

                    case SocketEventType.Log when eventArgs.GetData<SocketLogMessage>() is { } logMessage:
                        LogMessage?.Invoke(this, logMessage);
                        break;

                    case SocketEventType.MessageReceived when eventArgs.GetData<SocketClientMessage>() is { } message:
                        MessageReceived?.Invoke(this, message);
                        break;

                    case SocketEventType.HeartbeatTimeout when eventArgs.Data is Socket socket:
                        HeartbeatTimeout?.Invoke(this, socket);
                        break;

                    case SocketEventType.ClientDisconnected when eventArgs.Data is Socket socket:
                        ClientDisconnected?.Invoke(this, socket);
                        break;
                }
            }
            catch (Exception ex)
            {
                // 避免事件处理异常导致整个事件循环停止
                Debug.WriteLine($"事件处理异常: {ex.Message}");
            }
        }
    }

    public async ValueTask DisposeAsync()
    {
        if (_disposed) return;

        _disposed = true;
        _cts.Cancel();
        _eventChannel.Writer.TryComplete();

        _cts.Dispose();
        await Task.CompletedTask;
    }
}